package cc.wanforme.fsync.server.service.impl;

import cc.wanforme.fsync.entity.TickTaskVo;
import cc.wanforme.fsync.entity.po.GroupMap;
import cc.wanforme.fsync.entity.po.TickTask;
import cc.wanforme.fsync.entity.po.TickTaskGroup;
import cc.wanforme.fsync.server.mapper.GroupMapMapper;
import cc.wanforme.fsync.server.mapper.TickTaskGroupMapper;
import cc.wanforme.fsync.server.mapper.TickTaskMapper;
import cc.wanforme.fsync.server.service.ITickTaskService;
import cc.wanforme.fsync.task.CronTask;
import cc.wanforme.st.server.exception.MunkRuntimeException;
import cc.wanforme.st.server.util.AssertCheck;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
public class TickTaskServiceImpl extends ServiceImpl<TickTaskMapper, TickTask>
        implements ITickTaskService {

    private TickTaskGroupMapper tickTaskGroupMapper;
    private GroupMapMapper groupMapMapper;
    private CronTask cronTask;

    @Override
    public TickTask saveVo(TickTask vo) {
        String name = vo.getName();
        AssertCheck.nonNull(name, "Name is empty");
        // todo validate cron
        AssertCheck.nonNull(vo.getCron(), "Cron is empty");

        if (existedName(name, null)) {
            throw new MunkRuntimeException("Name '" + name + "' existed!");
        }

        this.save(vo);

        // 添加定时任务
        try {
            cronTask.setupCronTask(vo);
        } catch (SchedulerException e) {
            throw new MunkRuntimeException("定时任务开启失败！", e);
        }

        return vo;
    }

    @Override
    public TickTask updateVo(TickTask vo) {
        String name = vo.getName();
        AssertCheck.nonNull(vo.getId(), "unknown task");
        AssertCheck.nonNull(name, "Name is empty");
        // todo validate cron
        AssertCheck.nonNull(vo.getCron(), "Cron is empty");

        if (existedName(name, vo.getId())) {
            throw new MunkRuntimeException("Name '" + name + "' existed!");
        }

        this.updateById(vo);
        return vo;
    }

    @Override
    public void deleteVo(Long id) {
        TickTask tickTask = this.getById(id);
        try {
            cronTask.cancelTask(tickTask);
        } catch (SchedulerException e) {
            log.error("警告：定时任务取消失败！", e);
        }

        // 删除 task 与 groupMap 的关系
        tickTaskGroupMapper.deleteByTask(id);
        // 删除 task
        this.removeById(id);
    }

    /**
     * 判断 name 是否存在。 ignoreId 表示忽略的 id，更新时忽略自己。
     *
     * @param name
     * @param ignoreId
     * @return
     */
    private boolean existedName(String name, Long ignoreId) {
        TickTask task = this.baseMapper.getByName(name);
        if (task == null) {
            return false;
        }

        if (ignoreId != null && ignoreId.longValue() == task.getId().longValue()) {
            return false;
        }
        return true;
    }

    /** 修改 ticktask 的状态
     * @param taskId taskId
     * @param newActive 新的状态
     * @param compareOld 是否与旧状态比较。如果比较状态未变化，则不处理
     * */
    public void changeActive(Long taskId, Integer newActive, boolean compareOld) {
        AssertCheck.nonNull(taskId, "未知任务");

        TickTask task = this.getById(taskId);
        if(compareOld && Objects.equals(task.getActive(), newActive)) {
            return;
        }

        int active = newActive != null ? newActive.intValue() : 0;
        task.setActive(active);
        this.updateById(task);

        try {
            if (active == 1) {
                cronTask.setupCronTask(task);
            } else {
                boolean b = cronTask.cancelTask(task);
                if(!b) {
                    throw new MunkRuntimeException("任务删除失败！");
                }
            }
        } catch (SchedulerException e) {
            throw new MunkRuntimeException("定时任务" + (active==1?"开启":"关闭") + "失败!", e);
        }
    }

    @Override
    public List<TickTaskVo> listAllTasks() {
        List<TickTask> tasks = list();
        if (tasks == null) {
            return new ArrayList<>(0);
        }

        List<TickTaskVo> vos = new ArrayList<>(tasks.size());
        for (TickTask t : tasks) {
            TickTaskVo vo = new TickTaskVo();
            vo.setTask(t);

            // 获取关联的 GroupMap
            List<TickTaskGroup> taskGroups = tickTaskGroupMapper.listByTask(t.getId());
            if (tasks != null) {
                List<GroupMap> realGMs = new ArrayList<>();
                for (TickTaskGroup tg : taskGroups) {
                    GroupMap groupMap = groupMapMapper.selectById(tg.getGroupMapId());
                    if (groupMap != null) {
                        realGMs.add(groupMap);
                    }
                }
            }

            vos.add(vo);
        }

        return vos;
    }

    @Autowired
    public void setTickTaskGroupMapper(TickTaskGroupMapper tickTaskGroupMapper) {
        this.tickTaskGroupMapper = tickTaskGroupMapper;
    }

    @Autowired
    public void setGroupMapMapper(GroupMapMapper groupMapMapper) {
        this.groupMapMapper = groupMapMapper;
    }

    @Autowired
    @Lazy
    public void setCronTask(CronTask cronTask) {
        this.cronTask = cronTask;
    }
}
